#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifiiot_gpio.h"
#include "wifiiot_gpio_ex.h"
#include "hi_gpio.h"
#include "hi_io.h"
#include "hi_time.h"
#include "flower.h"


#define DHT11_GPIO  WIFI_IOT_IO_NAME_GPIO_14
//IO操作函数											   
#define	DHT11_DQ_OUT_High GpioSetOutputVal(DHT11_GPIO, 1); //设置GPIO输出高电平
#define	DHT11_DQ_OUT_Low GpioSetOutputVal(DHT11_GPIO, 0); //设置GPIO输出低电平  

WifiIotGpioValue DHT11_DQ_IN;
/****************************************
设置端口为输出
*****************************************/
void DHT11_IO_OUT(void)
{
    //设置GPIO_11为输出模式
    GpioSetDir(DHT11_GPIO, WIFI_IOT_GPIO_DIR_OUT);
}

//复位DHT11
void DHT11_Rst(void)	   
{                
	DHT11_IO_OUT(); 	//SET OUTPUT
   DHT11_DQ_OUT_Low; 	//拉低DQ
    hi_udelay(20000);//拉低至少18ms
   DHT11_DQ_OUT_High; 	//DQ=1 
	hi_udelay(35);     	//主机拉高20~40us
}

/****************************************
设置端口为输入
*****************************************/
void DHT11_IO_IN(void)
{
    GpioSetDir(DHT11_GPIO, WIFI_IOT_GPIO_DIR_IN);//配置为输入模式
    IoSetPull( DHT11_GPIO, WIFI_IOT_IO_PULL_NONE);//配置为浮空输入
}

//获取GPIO输入状态
uint8_t GPIOGETINPUT(WifiIotIoName id,WifiIotGpioValue *val)
{
    GpioGetInputVal(id,val);
    return *val;
}

//等待DHT11的回应
//返回1:未检测到DHT11的存在
//返回0:存在
uint8_t DHT11_Check(void) 	   
{   
	uint8_t retry=0;
	  DHT11_IO_IN();//SET INPUT	 
    while (GPIOGETINPUT(DHT11_GPIO,&DHT11_DQ_IN)&&retry<100)//DHT11会拉低40~80us
	{
		retry++;
		hi_udelay(1);
	};	 
	if(retry>=100)return 1;
	else retry=0;
    
    while ((!GPIOGETINPUT(DHT11_GPIO,&DHT11_DQ_IN))&&retry<100)//DHT11拉低后会再次拉高40~80us
	{
		retry++;
		hi_udelay(1);
	};
	if(retry>=100)return 1;	   
	return 0;
}

//初始化DHT11的IO口 DQ 同时检测DHT11的存在
//返回1:不存在
//返回0:存在    	 
uint8_t DHT11_Init(void)
{	 
	//初始化GPIO
    GpioInit();
    //设置GPIO_2的复用功能为普通GPIO
    IoSetFunc(WIFI_IOT_IO_NAME_GPIO_2, WIFI_IOT_IO_FUNC_GPIO_2_GPIO);
    //设置GPIO_2为输出模式
    GpioSetDir(WIFI_IOT_GPIO_IDX_2, WIFI_IOT_GPIO_DIR_OUT);
		 //设置GPIO_2输出高电平点亮LED灯
    GpioSetOutputVal(WIFI_IOT_GPIO_IDX_2, 1);
    //设置GPIO_11的复用功能为普通GPIO
	 IoSetFunc(DHT11_GPIO, WIFI_IOT_IO_FUNC_GPIO_14_GPIO);
    //设置GPIO_11为输出模式
    GpioSetDir(DHT11_GPIO, WIFI_IOT_GPIO_DIR_OUT);
		 //设置GPIO_11输出高电平
    GpioSetOutputVal(DHT11_GPIO, 1);		    
		DHT11_Rst();  //复位DHT11
		 return DHT11_Check();//等待DHT11的回应
} 

//从DHT11读取一个位
//返回值：1/0
uint8_t DHT11_Read_Bit(void) 			 
{
 	uint8_t retry=0;
  while(GPIOGETINPUT(DHT11_GPIO,&DHT11_DQ_IN)&&retry<100){//等待变为低电平
        retry++;
        hi_udelay(1);
    }
    retry=0;
    while((!GPIOGETINPUT(DHT11_GPIO,&DHT11_DQ_IN))&&retry<100){//等待变高电平
        retry++;
        hi_udelay(1);
    }
    hi_udelay(40);//等待40us	//用于判断高低电平，即数据1或0
    if(GPIOGETINPUT(DHT11_GPIO,&DHT11_DQ_IN))return 1; else return 0;
}
//从DHT11读取一个字节
//返回值：读到的数据
uint8_t DHT11_Read_Byte(void)    
{        
    uint8_t i,dat;
    dat=0;
	for (i=0;i<8;i++) 
	{
   		dat<<=1; 
	    dat|=DHT11_Read_Bit();
    }						    
    return dat;
}
//从DHT11读取一次数据
//temp:温度值(范围:0~50°)
//humi:湿度值(范围:20%~90%)
//返回值：0,正常;1,读取失败
uint8_t DHT11_Read_Data(uint8_t *temp_H,uint8_t *temp_L,uint8_t *humi_H,uint8_t *humi_L)    
{        
 	uint8_t buf[5]={ 0 };
	uint8_t i;
	DHT11_Rst();
	if(DHT11_Check()==0)
	{
		for(i=0;i<5;i++)//读取40位数据
		{
			buf[i]=DHT11_Read_Byte();
		}
		if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])//数据校验
		{
			*humi_H=buf[0];
            *humi_L=buf[1];
			*temp_H=buf[2];
			*temp_L=buf[3];
		}
	}else return 1;
	return 0;	    
}

static void TempHumiTask(void)
{
    while (DHT11_Init())
    {
        printf("No DHT11 Exist!\r\n");
    }

    while (1)
    {
        uint8_t temp_h,temp_l,humi_h,humi_l;
        if (DHT11_Read_Data(&temp_h,&temp_l,&humi_h,&humi_l)==0)
        {
            printf("Current humdity = %d.%d\%\r\n",humi_h,humi_l);
            printf("Current temperature = %d.%d C\r\n",temp_h,temp_l);
        }

        sleep(1);
    }
}

static void TempHumiEntry(void)
{
    osThreadAttr_t attr;

    attr.name = "TempHumiTask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 2048;
    attr.priority = 25;

    if (osThreadNew((osThreadFunc_t)TempHumiTask, NULL, &attr) == NULL)
    {
        printf("Falied to create LedTask!\n");
    }
}

APP_FEATURE_INIT(TempHumiEntry);